package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.ObjectUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.query.PointsBoardQuery;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.tianji.common.utils.DateUtils.DATE_SUFFIX_FORMATTER;
import static com.tianji.learning.constans.RedisConstans.POINTS_BOARD_KEY_PREFIX;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author wangyuqing
 * @since 2024-08-31
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;

    /**
     * 分页查询指定赛季积分排行榜
     *
     * @param query 分页参数；season：赛季id，为空或0时查询当前赛季；
     * @return
     */
    @Override
    public PointsBoardVO pageQueryPointsBoradBySeanson(PointsBoardQuery query) {
        //1.判断是否是查询当前赛季
        Long season = query.getSeason();
        boolean isCurrentSeason = ObjectUtils.isEmpty(season) || season == 0;
        //2.查询我的积分信息
        //2.1、组装查询key
        String key = POINTS_BOARD_KEY_PREFIX + LocalDateTime.now().format(DATE_SUFFIX_FORMATTER);
        //2.2、发起查询
        PointsBoard myBoard = isCurrentSeason ? queryMyCurrentBoard(key) : queryMyHisCurrentBoard(season);
        //3.查询指定赛季积分排行榜
        List<PointsBoard> boards = isCurrentSeason ? queryCurrentBoard(key, query.getPageNo(), query.getPageSize()) : queryHisCurrentBoard(query);
        //4.封装返回
        //4.1 封装我的积分信息
        PointsBoardVO myBoardVO = new PointsBoardVO();
        myBoardVO.setPoints(myBoard.getPoints());
        myBoardVO.setRank(myBoard.getRank());
        //4.2 封装积分排行榜
        if (CollUtils.isEmpty(boards)) {
            return myBoardVO;
        }
        //4.2.1 查询用户信息
        Set<Long> userIds = boards.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        List<UserDTO> userInfoList = userClient.queryUserByIds(userIds);
        //转Map
        Map<Long, String> collect = new HashMap<>(userIds.size());
        if (CollUtils.isNotEmpty(userInfoList)) {
            collect = userInfoList.stream().collect(Collectors.toMap(UserDTO::getId, UserDTO::getName));
        }
        // 4.2.2、循环组装item vo List
        List<PointsBoardItemVO> boardList = new ArrayList<>(boards.size());
        for (PointsBoard board : boards) {
            PointsBoardItemVO itemVO = new PointsBoardItemVO();
            itemVO.setPoints(board.getPoints());
            itemVO.setRank(board.getRank());
            itemVO.setName(collect.getOrDefault(board.getUserId(), ""));
            boardList.add(itemVO);
        }
        myBoardVO.setBoardList(boardList);
        return myBoardVO;
    }

    /**
     * 查询历史赛季积分排行榜
     *
     * @param query
     * @return
     */
    private List<PointsBoard> queryHisCurrentBoard(PointsBoardQuery query) {
        return null;
    }

    /**
     * 查询当前赛季积分排行榜
     * <p>
     * * @param key  redis zset key
     * * @param pageNo 查询第几页
     * * @param pageSize 一页查几条
     *
     * @return
     */
    private List<PointsBoard> queryCurrentBoard(String key, Integer pageNo, Integer pageSize) {
        //1.分页查询
        int from = (pageNo - 1) * pageSize;
        int end = from + pageSize - 1;
        //调用zset中reverseRangeWithScores方法查询排名与分数，有序排序
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, from, end);
        if (ObjectUtils.isEmpty(typedTuples)) {
            return CollUtils.emptyList();
        }
        //2.封装list返回
        List<PointsBoard> list = new ArrayList<>();
        int rank = from + 1;
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            //3.1、获取用户id
            String userId = tuple.getValue();
            //3.2、获取积分
            Double points = tuple.getScore();
            if (ObjectUtils.isEmpty(points) || ObjectUtils.isEmpty(userId)) {
                continue;
            }
            //3.3、封装对象
            PointsBoard board = new PointsBoard();
            board.setPoints(points.intValue());
            board.setUserId(Long.valueOf(userId));
            board.setRank(rank++);
            list.add(board);
        }

        return list;
    }

    /**
     * 查询我的历史赛季积分信息
     *
     * @param season 赛季信息
     * @return
     */
    private PointsBoard queryMyHisCurrentBoard(Long season) {
        return null;
    }

    /**
     * 查询我的本赛季积分信息
     *
     * @param key
     * @return
     */
    private PointsBoard queryMyCurrentBoard(String key) {
        BoundZSetOperations<String, String> zSetOps = redisTemplate.boundZSetOps(key);
        Long userId = UserContext.getUser();
        //1.查询我的积分信息
        Double score = zSetOps.score(userId.toString());
        //2.查询我的排名信息
        Long rank = zSetOps.reverseRank(userId.toString());
        //3.封装返回
        PointsBoard board = new PointsBoard();
        board.setPoints(score == null ? 0 : score.intValue());
        board.setRank(rank == null ? 0 : rank.intValue() + 1);
        return board;
    }
}
